import 'package:flutter/material.dart';

class GridWrap extends StatelessWidget {
  final Axis direction;
  final double spacing;
  final double runSpacing;
  final TextDirection? textDirection;
  final VerticalDirection verticalDirection;
  final Clip clipBehavior;
  final int crossAxisCount;
  final double aspectRatio;
  final List<Widget> children;
  GridWrap({
    Key? key,
    this.direction = Axis.horizontal,
    this.spacing = 0.0,
    this.runSpacing = 0.0,
    this.crossAxisCount = 4,
    this.aspectRatio = 1,
    this.textDirection,
    this.verticalDirection = VerticalDirection.down,
    this.clipBehavior = Clip.none,
    children = const <Widget>[],
  })  : children = children
            .map<Widget>((item) => AspectRatio(
                  aspectRatio: aspectRatio,
                  child: item,
                ))
            .toList(),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    int cid = 0;
    return CustomMultiChildLayout(
      delegate: _GridWrapDelegate(this),
      children: children
          .map<LayoutId>((item) => LayoutId(id: cid++, child: item))
          .toList(),
    );
  }
}

class _GridWrapDelegate extends MultiChildLayoutDelegate {
  final GridWrap widget;
  double layoutHeight = 0;
  late double itemWidth, itemHeight;

  _GridWrapDelegate(this.widget);

  int get childCount => widget.children.length;
  int get row => (childCount / widget.crossAxisCount).ceil();

  @override
  Size getSize(BoxConstraints constraints) => Size(
      constraints.maxWidth,
      row *
          ((constraints.maxWidth + widget.spacing) / widget.crossAxisCount -
              widget.spacing) *
          widget.aspectRatio);

  @override
  void performLayout(Size size) {
    double dx = 0.0, dy = 0.0;
    itemWidth =
        (size.width + widget.spacing) / widget.crossAxisCount - widget.spacing;
    itemHeight = itemWidth * widget.aspectRatio;
    final itemSize = BoxConstraints.tight(Size(itemWidth, itemHeight));

    for (int i = 0; i <= row; i++) {
      dx = 0;
      for (int j = 0; j < widget.crossAxisCount; j++) {
        int childId = i * widget.crossAxisCount + j;
        if (hasChild(childId)) {
          //logger.info("$dx, $dy");
          positionChild(childId, Offset(dx, dy));
          layoutChild(childId, itemSize);
        }
        dx += itemWidth + widget.spacing;
      }
      dy += itemHeight + widget.runSpacing;
    }
    layoutHeight = dy;
  }

  @override
  bool shouldRelayout(covariant _GridWrapDelegate oldDelegate) =>
      oldDelegate.widget.aspectRatio != widget.aspectRatio ||
      oldDelegate.widget.children.length != widget.children.length ||
      oldDelegate.widget.spacing != widget.spacing ||
      oldDelegate.widget.runSpacing != widget.runSpacing ||
      oldDelegate.widget.direction != widget.direction ||
      oldDelegate.widget.verticalDirection != widget.verticalDirection;
}
